home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume17 / delete / part03 < prev    next >
Encoding:
Internet Message Format  |  1991-02-25  |  31.8 KB

  1. From: jik@pit-manager.MIT.EDU (Jonathan I. Kamens)
  2. Newsgroups: comp.sources.misc
  3. Subject: v17i025:  delete - MIT Athena delete/undelete programs, Part03/04
  4. Message-ID: <1991Feb25.180745.4388@sparky.IMD.Sterling.COM>
  5. Date: 25 Feb 91 18:07:45 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 4d4519fb fb8b274b 79427acf e56367e9
  8.  
  9. Submitted-by: Jonathan I. Kamens <jik@pit-manager.MIT.EDU>
  10. Posting-number: Volume 17, Issue 25
  11. Archive-name: delete/part03
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then unpack
  15. # it by saving it into a file and typing "sh file".  To overwrite existing
  16. # files, type "sh file -c".  You can also feed this as standard input via
  17. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  18. # will see the following message at the end:
  19. #        "End of archive 3 (of 4)."
  20. # Contents:  delete.c directories.c
  21. # Wrapped by jik@pit-manager on Fri Feb 22 08:14:26 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f 'delete.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'delete.c'\"
  25. else
  26. echo shar: Extracting \"'delete.c'\" \(13684 characters\)
  27. sed "s/^X//" >'delete.c' <<'END_OF_FILE'
  28. X/*
  29. X * $Source: /afs/athena.mit.edu/astaff/project/delete/src/RCS/delete.c,v $
  30. X * $Author: jik $
  31. X *
  32. X * This program is a replacement for rm.  Instead of actually deleting
  33. X * files, it marks them for deletion by prefixing them with a ".#"
  34. X * prefix.
  35. X *
  36. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  37. X * For copying and distribution information, see the file "mit-copyright.h."
  38. X */
  39. X
  40. X#if (!defined(lint) && !defined(SABER))
  41. X     static char rcsid_delete_c[] = "$Header: /afs/athena.mit.edu/astaff/project/delete/src/RCS/delete.c,v 1.24 91/02/20 17:24:51 jik Exp $";
  42. X#endif
  43. X
  44. X#include <sys/types.h>
  45. X#include <stdio.h>
  46. X#include <sys/dir.h>
  47. X#ifdef SYSV
  48. X#include <string.h>
  49. X#define index strchr
  50. X#define rindex strrchr
  51. X#else
  52. X#include <strings.h>
  53. X#endif /* SYSV */
  54. X#include <sys/param.h>
  55. X#include <sys/file.h>
  56. X#include <errno.h>
  57. X#include "errors.h"
  58. X#include "delete_errs.h"
  59. X#include "util.h"
  60. X#include "delete.h"
  61. X#include "mit-copyright.h"
  62. X
  63. X
  64. X
  65. X/*
  66. X * ALGORITHM:
  67. X *
  68. X * 1. Parse command-line arguments and set flags.
  69. X * 2. Call the function delete() for each filename command-line argument.
  70. X *
  71. X * delete():
  72. X *
  73. X * 1. Can the file be lstat'd?
  74. X *    no -- abort
  75. X *    yes -- continue
  76. X * 2. Is the file a directory?
  77. X *    yes -- is it a dotfile?
  78. X *           yes -- abort
  79. X *           no -- continue
  80. X *        -- is the filesonly option set?
  81. X *           yes -- is the recursive option specified?
  82. X *                  yes -- continue
  83. X *                  no -- abort
  84. X *           no -- is the directory empty?
  85. X *                  yes -- remove it
  86. X *                  no -- is the directoriesonly option set?
  87. X *               yes -- abort
  88. X *               no -- continue
  89. X *                -- is the recursive option specified?
  90. X *               yes -- continue
  91. X *               no -- abort
  92. X *    no -- is the directoriesonly option set?
  93. X *         yes -- abort
  94. X *         no -- continue
  95. X * 3. If the file is a file, remove it.
  96. X * 4. If the file is a directory, open it and pass each of its members
  97. X *    (excluding . files) to delete().
  98. X */
  99. X
  100. X
  101. Xint force, interactive, recursive, noop, verbose, filesonly, directoriesonly;
  102. Xint emulate_rm, linked_to_rm, linked_to_rmdir;
  103. Xextern int errno;
  104. X
  105. Xmain(argc, argv)
  106. Xint argc;
  107. Xchar *argv[];
  108. X{
  109. X     extern char *optarg;
  110. X     extern int optind;
  111. X     int arg;
  112. X     
  113. X     whoami = lastpart(argv[0]);
  114. X
  115. X     initialize_del_error_table();
  116. X     
  117. X     force = interactive = recursive = noop = verbose = filesonly =
  118. X      directoriesonly = emulate_rm = linked_to_rm = linked_to_rmdir = 0;
  119. X
  120. X     if (!strcmp(whoami, "rm"))
  121. X      emulate_rm++, filesonly++, linked_to_rm++;
  122. X     if (!strcmp(whoami, "rmdir") || !strcmp(whoami, "rd"))
  123. X      emulate_rm++, directoriesonly++, linked_to_rmdir++;
  124. X     
  125. X     while ((arg = getopt(argc, argv, "efirnvFD")) != -1) {
  126. X      switch (arg) {
  127. X      case 'r':
  128. X           recursive++;
  129. X           if (directoriesonly) {
  130. X                    fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
  131. X                            whoami);
  132. X                    usage();
  133. X            exit(1);
  134. X           }
  135. X           break;
  136. X      case 'f':
  137. X           force++;
  138. X           break;
  139. X      case 'i':
  140. X           interactive++;
  141. X           break;
  142. X      case 'n':
  143. X           noop++;
  144. X           break;
  145. X      case 'v':
  146. X           verbose++;
  147. X           break;
  148. X      case 'e':
  149. X           emulate_rm++;
  150. X           break;
  151. X      case 'F':
  152. X           filesonly++;
  153. X           if (directoriesonly) {
  154. X            fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
  155. X                            whoami);
  156. X                    usage();
  157. X            exit(1);
  158. X           }
  159. X           break;
  160. X      case 'D':
  161. X           directoriesonly++;
  162. X           if (recursive) {
  163. X                    fprintf(stderr, "%s: -r and -D are mutually exclusive.\n",
  164. X                            whoami);
  165. X                    usage();
  166. X            exit(1);
  167. X           }
  168. X           if (filesonly) {
  169. X                    fprintf(stderr, "%s: -F and -D are mutually exclusive.\n",
  170. X                            whoami);
  171. X                    usage();
  172. X            exit(1);
  173. X           }
  174. X           break;
  175. X      default:
  176. X           usage();
  177. X           exit(1);
  178. X      }
  179. X     }
  180. X     report_errors = ! (force || emulate_rm);
  181. X     
  182. X     if (optind == argc) {
  183. X      if (! force) {
  184. X           fprintf(stderr, "%s: no files specified.\n", whoami);
  185. X           usage();
  186. X      }
  187. X      exit(force ? 0 : 1);
  188. X     }
  189. X     while (optind < argc) {
  190. X      if (delete(argv[optind], 0))
  191. X           error(argv[optind]);
  192. X      optind++;
  193. X     }
  194. X     exit(((! force) && error_occurred) ? 1 : 0);
  195. X}
  196. X
  197. X
  198. X
  199. Xusage()
  200. X{
  201. X     printf("Usage: %s [ options ] filename ...\n", whoami);
  202. X     printf("Options are:\n");
  203. X     if (! linked_to_rmdir)
  204. X      printf("     -r     recursive\n");
  205. X     printf("     -i     interactive\n");
  206. X     printf("     -f     force\n");
  207. X     printf("     -n     noop\n");
  208. X     printf("     -v     verbose\n");
  209. X     if (! (linked_to_rmdir || linked_to_rm)) {
  210. X      printf("     -e     emulate rm/rmdir\n");
  211. X      printf("     -F     files only\n");
  212. X      printf("     -D     directories only\n");
  213. X     }
  214. X     printf("     --     end options and start filenames\n");
  215. X     if (! (linked_to_rmdir || linked_to_rm)) {
  216. X      printf("-r and -D are mutually exclusive\n");
  217. X      printf("-F and -D are mutually exclusive\n");
  218. X     }
  219. X}
  220. X
  221. X
  222. X
  223. X
  224. Xdelete(filename, recursed)
  225. Xchar *filename;
  226. Xint recursed;
  227. X{
  228. X     struct stat stat_buf;
  229. X     int retval;
  230. X     
  231. X     /* can the file be lstat'd? */
  232. X     if (lstat(filename, &stat_buf) == -1) {
  233. X      set_error(errno);
  234. X      if (emulate_rm && (! force))
  235. X           fprintf(stderr, "%s: %s nonexistent\n", whoami, filename);
  236. X      error(filename);
  237. X      return error_code;
  238. X     }
  239. X
  240. X     /* is the file a directory? */
  241. X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  242. X      /* is the file a dot file? */
  243. X      if (is_dotfile(lastpart(filename))) {
  244. X           set_error(DELETE_IS_DOTFILE);
  245. X           if (emulate_rm && (! force))
  246. X            fprintf(stderr, "%s: cannot remove `.' or `..'\n", whoami);
  247. X           error(filename);
  248. X           return error_code;
  249. X      }
  250. X
  251. X      /* is the filesonly option set? */
  252. X      if (filesonly) {
  253. X           /* is the recursive option specified? */
  254. X           if (recursive) {
  255. X            if (retval = recursive_delete(filename, stat_buf,
  256. X                          recursed)) {
  257. X             error(filename);
  258. X             return retval;
  259. X            }
  260. X           }
  261. X           else {
  262. X            if (emulate_rm && (! force))
  263. X             fprintf(stderr, "%s: %s directory\n", whoami,
  264. X                 filename);
  265. X            set_error(DELETE_CANT_DEL_DIR);
  266. X            error(filename);
  267. X            return error_code;
  268. X           }
  269. X      }
  270. X      else {
  271. X           /* is the directory empty? */
  272. X           if ((retval = empty_directory(filename)) < 0) {
  273. X            error(filename);
  274. X            if (! emulate_rm)
  275. X             return error_code;
  276. X           }
  277. X
  278. X           if (retval > 0) {
  279. X            /* remove it */
  280. X            if (retval = do_move(filename, stat_buf, 0)) {
  281. X             error(filename);
  282. X             return error_code;
  283. X            }
  284. X           }
  285. X           else {
  286. X            /* is the directoriesonly option set? */
  287. X            if (directoriesonly) {
  288. X             if (emulate_rm && (! force))
  289. X                  fprintf(stderr, "%s: %s: Directory not empty\n",
  290. X                      whoami, filename);
  291. X             set_error(DELETE_DIR_NOT_EMPTY);
  292. X             error(filename);
  293. X             return error_code;
  294. X            }
  295. X            else {
  296. X             /* is the recursive option specified? */
  297. X             if (recursive) {
  298. X                  if (retval = recursive_delete(filename, stat_buf,
  299. X                                recursed)) {
  300. X                   error(filename);
  301. X                   return error_code;
  302. X                  }
  303. X             }
  304. X             else {
  305. X                  if (emulate_rm && (! force))
  306. X                   fprintf(stderr, "%s: %s not empty\n",
  307. X                       whoami, filename);
  308. X                  set_error(DELETE_DIR_NOT_EMPTY);
  309. X                  error(filename);
  310. X                  return error_code;
  311. X             }
  312. X            }
  313. X           }
  314. X      }
  315. X     }
  316. X     else {
  317. X      /* is the directoriesonly option set? */
  318. X      if (directoriesonly) {
  319. X           if (emulate_rm && (! force))
  320. X            fprintf(stderr, "%s: %s: Not a directory\n", whoami,
  321. X                filename);
  322. X           set_error(DELETE_CANT_DEL_FILE);
  323. X           error(filename);
  324. X           return error_code;
  325. X      }
  326. X      else {
  327. X           if (retval = do_move(filename, stat_buf, 0)) {
  328. X            error(filename);
  329. X            return error_code;
  330. X           }
  331. X      }
  332. X     }
  333. X     return 0;
  334. X}
  335. X      
  336. X
  337. X         
  338. X             
  339. X           
  340. Xempty_directory(filename)
  341. Xchar *filename;
  342. X{
  343. X     DIR *dirp;
  344. X     struct direct *dp;
  345. X
  346. X     dirp = Opendir(filename);
  347. X     if (! dirp) {
  348. X      set_error(errno);
  349. X      error(filename);
  350. X      return -1;
  351. X     }
  352. X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  353. X      if (is_dotfile(dp->d_name))
  354. X           continue;
  355. X      if (is_deleted(dp->d_name))
  356. X           continue;
  357. X      else {
  358. X           closedir(dirp);
  359. X           return 0;
  360. X      }
  361. X     }
  362. X     closedir(dirp);
  363. X     return 1;
  364. X}
  365. X
  366. X
  367. X
  368. X
  369. Xrecursive_delete(filename, stat_buf, recursed)
  370. Xchar *filename;
  371. Xstruct stat stat_buf;
  372. Xint recursed;
  373. X{
  374. X     DIR *dirp;
  375. X     struct direct *dp;
  376. X     int status = 0;
  377. X     char newfile[MAXPATHLEN];
  378. X     int retval = 0;
  379. X     
  380. X     if (interactive && recursed) {
  381. X      printf("%s: remove directory %s? ", whoami, filename);
  382. X      if (! yes()) {
  383. X           set_status(DELETE_NOT_DELETED);
  384. X           return error_code;
  385. X      }
  386. X     }
  387. X     dirp = Opendir(filename);
  388. X     if (! dirp) {
  389. X      if (emulate_rm && (! force))
  390. X           fprintf(stderr, "%s: %s not changed\n", whoami, filename);
  391. X      set_error(errno);
  392. X      error(filename);
  393. X      return error_code;
  394. X     }
  395. X     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  396. X      if (is_dotfile(dp->d_name))
  397. X           continue;
  398. X      if (is_deleted(dp->d_name))
  399. X           continue;
  400. X      else {
  401. X           (void) strcpy(newfile, append(filename, dp->d_name));
  402. X           if (! *newfile) {
  403. X            error(filename);
  404. X            status = error_code;
  405. X           }
  406. X
  407. X           retval = delete(newfile, 1);
  408. X           if (retval) {
  409. X            error(newfile);
  410. X            status = retval;
  411. X           }
  412. X      }
  413. X     }
  414. X     closedir(dirp);
  415. X
  416. X     if (status && (! emulate_rm)) {
  417. X      set_warning(DELETE_DIR_NOT_EMPTY);
  418. X      error(filename);
  419. X     }
  420. X     else
  421. X      retval = do_move(filename, stat_buf, status);
  422. X     
  423. X     if (retval)
  424. X      status = retval;
  425. X
  426. X     return status;
  427. X}
  428. X
  429. X                     
  430. X
  431. X
  432. X
  433. X
  434. Xdo_move(filename, stat_buf, subs_not_deleted)
  435. Xchar *filename;
  436. Xstruct stat stat_buf;
  437. Xint subs_not_deleted; /* If the file in question is a directory, and  */
  438. X              /* there is something underneath it that hasn't */
  439. X              /* been removed, this will be set to true.      */
  440. X                      /* The program asks if the user wants to delete */
  441. X              /* the directory, and if the user says yes,     */
  442. X              /* checks the value of subs_not_deleted.  If    */
  443. X              /* it's true, an error results.                 */
  444. X                      /* This is used only when emulating rm.         */
  445. X{
  446. X     char *last;
  447. X     char buf[MAXPATHLEN];
  448. X     char name[MAXNAMLEN];
  449. X     struct stat deleted_buf;
  450. X
  451. X     (void) strncpy(buf, filename, MAXPATHLEN);
  452. X     last = lastpart(buf);
  453. X     if (strlen(last) > MAXNAMLEN) {
  454. X      if (emulate_rm && (! force))
  455. X           fprintf(stderr, "%s: %s: filename too long\n", whoami,
  456. X               filename);
  457. X      set_error(ENAMETOOLONG);
  458. X      error(filename);
  459. X      return error_code;
  460. X     }
  461. X     (void) strcpy(name, last);
  462. X     if (strlen(buf) + 3 > MAXPATHLEN) {
  463. X      if (emulate_rm && (! force))
  464. X           fprintf(stderr, "%s: %s: pathname too long\n", whoami,
  465. X               filename);
  466. X      set_error(ENAMETOOLONG);
  467. X      error(filename);
  468. X      return error_code;
  469. X     }
  470. X     *last = '\0';
  471. X     (void) strcat(buf, ".#");
  472. X     (void) strcat(buf, name);
  473. X     if (interactive) {
  474. X      printf("%s: remove %s? ", whoami, filename);
  475. X      if (! yes()) {
  476. X           set_status(DELETE_NOT_DELETED);
  477. X           return error_code;
  478. X      }
  479. X     }
  480. X     else if ((! force)
  481. X#ifdef S_IFLNK
  482. X          && ((stat_buf.st_mode & S_IFMT) != S_IFLNK)
  483. X#endif
  484. X          && access(filename, W_OK)) {
  485. X      if (emulate_rm)
  486. X           printf("%s: override protection %o for %s? ", whoami,
  487. X              stat_buf.st_mode & 0777, filename);
  488. X      else
  489. X           printf("%s: File %s not writeable.  Delete anyway? ", whoami,
  490. X              filename);
  491. X      if (! yes()) {
  492. X           set_status(DELETE_NOT_DELETED);
  493. X           return error_code;
  494. X      }
  495. X     }
  496. X     if (emulate_rm && subs_not_deleted) {
  497. X      if (! force)
  498. X           fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  499. X      return 1;
  500. X     }
  501. X     if (noop) {
  502. X      fprintf(stderr, "%s: %s would be removed\n", whoami, filename);
  503. X      return 0;
  504. X     }
  505. X     if ((! lstat(buf, &deleted_buf)) && unlink_completely(buf)) {
  506. X      if (emulate_rm && (! force))
  507. X           fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  508. X      error(filename);
  509. X      return error_code;
  510. X     }
  511. X     if (rename(filename, buf)) {
  512. X      if (emulate_rm && (! force))
  513. X           fprintf(stderr, "%s: %s not removed\n", whoami, filename);
  514. X      set_error(errno);
  515. X      error(filename);
  516. X      return error_code;
  517. X     }
  518. X     else {
  519. X      if (verbose)
  520. X           fprintf(stderr, "%s: %s removed\n", whoami, filename);
  521. X      return 0;
  522. X     }
  523. X}
  524. X
  525. X
  526. X
  527. Xunlink_completely(filename)
  528. Xchar *filename;
  529. X{
  530. X     char buf[MAXPATHLEN];
  531. X     struct stat stat_buf;
  532. X     DIR *dirp;
  533. X     struct direct *dp;
  534. X     int status = 0;
  535. X     int retval;
  536. X     
  537. X     if (lstat(filename, &stat_buf)) {
  538. X      set_error(errno);
  539. X      error(filename);
  540. X      return error_code;
  541. X     }
  542. X
  543. X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  544. X      dirp = Opendir(filename);
  545. X      if (! dirp) {
  546. X           set_error(errno);
  547. X           error(filename);
  548. X           return error_code;
  549. X      }
  550. X      
  551. X      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  552. X           if (is_dotfile(dp->d_name))
  553. X            continue;
  554. X           (void) strcpy(buf, append(filename, dp->d_name));
  555. X           if (! *buf) {
  556. X            status = error_code;
  557. X            error(filename);
  558. X            continue;
  559. X           }
  560. X           retval = unlink_completely(buf);
  561. X           if (retval) {
  562. X            status = retval;
  563. X            error(filename);
  564. X           }
  565. X      }
  566. X      closedir(dirp);
  567. X
  568. X      if (status)
  569. X           return status;
  570. X
  571. X      retval = rmdir(filename);
  572. X      if (retval) {
  573. X           set_error(errno);
  574. X           error(filename);
  575. X           return errno;
  576. X      }
  577. X     }
  578. X     else {
  579. X      retval = unlink(filename);
  580. X      if (retval) {
  581. X           set_error(errno);
  582. X           error(filename);
  583. X           return error_code;
  584. X      }
  585. X      else
  586. X           return 0;
  587. X     }
  588. X     return 0;
  589. X}
  590. END_OF_FILE
  591. if test 13684 -ne `wc -c <'delete.c'`; then
  592.     echo shar: \"'delete.c'\" unpacked with wrong size!
  593. fi
  594. # end of 'delete.c'
  595. fi
  596. if test -f 'directories.c' -a "${1}" != "-c" ; then 
  597.   echo shar: Will not clobber existing file \"'directories.c'\"
  598. else
  599. echo shar: Extracting \"'directories.c'\" \(15169 characters\)
  600. sed "s/^X//" >'directories.c' <<'END_OF_FILE'
  601. X/*
  602. X * $Source: /afs/athena.mit.edu/user/j/jik/delete/src/RCS/directories.c,v $
  603. X * $Author: jik $
  604. X * 
  605. X * This program is part of a package including delete, undelete,
  606. X * lsdel, expunge and purge.  The software suite is meant as a
  607. X * replacement for rm which allows for file recovery.
  608. X * 
  609. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  610. X * For copying and distribution information, see the file "mit-copyright.h."
  611. X */
  612. X
  613. X#if !defined(lint) && !defined(SABER)
  614. X     static char rcsid_directories_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/delete/src/RCS/directories.c,v 1.18 91/02/22 06:32:25 jik Exp $";
  615. X#endif
  616. X
  617. X#include <stdio.h>
  618. X#include <sys/types.h>
  619. X#include <sys/param.h>
  620. X#include <sys/dir.h>
  621. X#ifdef SYSV
  622. X#include <string.h>
  623. X#define index strchr
  624. X#define rindex strrchr
  625. X#else
  626. X#include <strings.h>
  627. X#endif /* SYSV */
  628. X#include <errno.h>
  629. X#include <com_err.h>
  630. X#include "delete_errs.h"
  631. X#include "util.h"
  632. X#include "directories.h"
  633. X#include "mit-copyright.h"
  634. X#include "errors.h"
  635. X
  636. Xextern char *realloc();
  637. Xextern long time();
  638. Xextern int errno;
  639. X
  640. Xstatic filerec root_tree;
  641. Xstatic filerec cwd_tree;
  642. X
  643. Xvoid free_leaf();
  644. X
  645. X /* These are not static because external routines need to be able to */
  646. X /* access them.                               */
  647. Xtime_t current_time;
  648. X
  649. X
  650. Xstatic filerec default_cwd = {
  651. X     "",
  652. X     (filerec *) NULL,
  653. X     (filerec *) NULL,
  654. X     (filerec *) NULL,
  655. X     (filerec *) NULL,
  656. X     (filerec *) NULL,
  657. X     False,
  658. X     False,
  659. X     {0}
  660. X};
  661. X
  662. Xstatic filerec default_root = {
  663. X     "/",
  664. X     (filerec *) NULL,
  665. X     (filerec *) NULL,
  666. X     (filerec *) NULL,
  667. X     (filerec *) NULL,
  668. X     (filerec *) NULL,
  669. X     False,
  670. X     False,
  671. X     {0}
  672. X};
  673. X
  674. Xstatic filerec default_directory = {
  675. X     "",
  676. X     (filerec *) NULL,
  677. X     (filerec *) NULL,
  678. X     (filerec *) NULL,
  679. X     (filerec *) NULL,
  680. X     (filerec *) NULL,
  681. X     False,
  682. X     False,
  683. X     {0}
  684. X};
  685. X
  686. Xstatic filerec default_file = {
  687. X     "",
  688. X     (filerec *) NULL,
  689. X     (filerec *) NULL,
  690. X     (filerec *) NULL,
  691. X     (filerec *) NULL,
  692. X     (filerec *) NULL,
  693. X     False,
  694. X     False,
  695. X     {0}
  696. X};
  697. X
  698. X
  699. Xfilerec *get_root_tree()
  700. X{
  701. X     return(&root_tree);
  702. X}
  703. X
  704. X
  705. X
  706. Xfilerec *get_cwd_tree()
  707. X{
  708. X     return(&cwd_tree);
  709. X}
  710. X
  711. X
  712. Xint initialize_tree()
  713. X{
  714. X     int retval;
  715. X     
  716. X     root_tree = default_root;
  717. X     cwd_tree = default_cwd;
  718. X
  719. X     current_time = time((time_t *)0);
  720. X     if (retval = get_specs(".", &cwd_tree.specs, FOLLOW_LINKS)) {
  721. X      error("get_specs on .");
  722. X      return retval;
  723. X     }
  724. X     if (retval = get_specs("/", &root_tree.specs, FOLLOW_LINKS)) {
  725. X      error("get_specs on /");
  726. X      return retval;
  727. X     }
  728. X     return 0;
  729. X}
  730. X
  731. X
  732. Xint add_path_to_tree(path, leaf)
  733. Xchar *path;
  734. Xfilerec **leaf;
  735. X{
  736. X     filerec *parent;
  737. X     char next_name[MAXNAMLEN];
  738. X     char lpath[MAXPATHLEN], built_path[MAXPATHLEN], *ptr;
  739. X     struct mystat specs;
  740. X     int retval;
  741. X     
  742. X     if (retval = get_specs(path, &specs, DONT_FOLLOW_LINKS)) {
  743. X      char error_buf[MAXPATHLEN+14];
  744. X
  745. X      (void) sprintf(error_buf, "get_specs on %s", path);
  746. X      error(error_buf);
  747. X      return retval;
  748. X     }
  749. X     
  750. X     (void) strcpy(lpath, path); /* we don't want to damage the user's */
  751. X                 /* string */
  752. X     ptr = lpath;
  753. X     if (*ptr == '/') {
  754. X      parent = &root_tree;
  755. X      ptr++;
  756. X      (void) strcpy(built_path, "/");
  757. X     }
  758. X     else if (! strncmp(ptr, "./", 2)) {
  759. X      parent = &cwd_tree;
  760. X      ptr += 2;
  761. X      *built_path = '\0';
  762. X     }
  763. X     else {
  764. X      parent = &cwd_tree;
  765. X      *built_path = '\0';
  766. X     }
  767. X     
  768. X     (void) strcpy(next_name, firstpart(ptr, ptr));
  769. X     while (*ptr) {
  770. X      (void) strcat(built_path, next_name);
  771. X      if (retval = add_directory_to_parent(parent, next_name, False,
  772. X                           &parent)) {
  773. X           error("add_directory_to_parent");
  774. X           return retval;
  775. X      }
  776. X      (void) strcpy(next_name, firstpart(ptr, ptr));
  777. X      if (retval = get_specs(built_path, &parent->specs, FOLLOW_LINKS)) {
  778. X           char error_buf[MAXPATHLEN+14];
  779. X
  780. X           (void) sprintf(error_buf, "get_specs on %s", built_path);
  781. X           error(error_buf);
  782. X           return retval;
  783. X      }
  784. X      (void) strcat(built_path, "/");
  785. X     }
  786. X     if ((specs.st_mode & S_IFMT) == S_IFDIR) {
  787. X      retval = add_directory_to_parent(parent, next_name, True, leaf);
  788. X      if (retval) {
  789. X           error("add_directory_to_parent");
  790. X           return retval;
  791. X      }
  792. X     }
  793. X     else {
  794. X      retval = add_file_to_parent(parent, next_name, True, leaf);
  795. X      if (retval) {
  796. X           error("add_file_to_parent");
  797. X           return retval;
  798. X      }
  799. X     }          
  800. X
  801. X     (*leaf)->specs = specs;
  802. X
  803. X     return 0;
  804. X}
  805. X
  806. X
  807. X
  808. Xint get_specs(path, specs, follow)
  809. Xchar *path;
  810. Xstruct mystat *specs;
  811. Xint follow; /* follow symlinks or not? */
  812. X{
  813. X     int status;
  814. X     struct stat realspecs;
  815. X     
  816. X     if (strlen(path)) if ((path[strlen(path) - 1] == '/') &&
  817. X               (strlen(path) != 1))
  818. X      path[strlen(path) - 1] = '\0';
  819. X     if (follow == FOLLOW_LINKS)
  820. X      status = stat(path, &realspecs);
  821. X     else 
  822. X      status = lstat(path, &realspecs);
  823. X
  824. X     if (status) {
  825. X      set_error(errno);
  826. X      error(path);
  827. X      return error_code;
  828. X     }
  829. X
  830. X     specs->st_dev = realspecs.st_dev;
  831. X     specs->st_ino = realspecs.st_ino;
  832. X     specs->st_mode = realspecs.st_mode;
  833. X     specs->st_size = realspecs.st_size;
  834. X     specs->st_ctime = realspecs.st_ctime;
  835. X#ifdef notdef
  836. X     /*
  837. X      * See comment in directories.h to understand why this is
  838. X      * disabled.
  839. X      */
  840. X     specs->st_blocks = realspecs.st_blocks;
  841. X#endif
  842. X
  843. X     return 0;
  844. X}
  845. X
  846. X
  847. X
  848. Xfilerec *next_leaf(leaf)
  849. Xfilerec *leaf;
  850. X{
  851. X     filerec *new;
  852. X
  853. X     if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
  854. X      new = first_in_directory(leaf);
  855. X      if (new)
  856. X           return(new);
  857. X      new = next_directory(leaf);
  858. X      return(new);
  859. X     }
  860. X     else {
  861. X      new = next_in_directory(leaf);
  862. X      return(new);
  863. X     }
  864. X}
  865. X
  866. X
  867. Xfilerec *next_specified_leaf(leaf)
  868. Xfilerec *leaf;
  869. X{
  870. X     while (leaf = next_leaf(leaf))
  871. X     if (leaf->specified)
  872. X      return(leaf);
  873. X     return((filerec *) NULL);
  874. X}
  875. X
  876. X
  877. Xfilerec *next_directory(leaf)
  878. Xfilerec *leaf;
  879. X{
  880. X     filerec *ret;
  881. X     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
  882. X      leaf = leaf->parent;
  883. X     if (leaf)
  884. X      ret = leaf->next;
  885. X     else
  886. X      ret = (filerec *) NULL;
  887. X     if (ret) if (ret->freed)
  888. X      ret = next_directory(ret);
  889. X     return(ret);
  890. X}
  891. X
  892. X
  893. Xfilerec *next_specified_directory(leaf)
  894. Xfilerec *leaf;
  895. X{
  896. X     while (leaf = next_directory(leaf))
  897. X      if (leaf->specified)
  898. X           return(leaf);
  899. X     return ((filerec *) NULL);
  900. X}
  901. X
  902. X
  903. X
  904. Xfilerec *next_in_directory(leaf)
  905. Xfilerec *leaf;
  906. X{
  907. X     filerec *ret;
  908. X
  909. X     if (leaf->next)
  910. X      ret = leaf->next;
  911. X     else if (((leaf->specs.st_mode & S_IFMT) != S_IFDIR) && leaf->parent)
  912. X      ret = leaf->parent->dirs;
  913. X     else
  914. X      ret = (filerec *) NULL;
  915. X     if (ret) if (ret->freed)
  916. X      ret = next_in_directory(ret);
  917. X     return (ret);
  918. X}
  919. X
  920. X
  921. X
  922. X
  923. Xfilerec *next_specified_in_directory(leaf)
  924. Xfilerec *leaf;
  925. X{
  926. X     while (leaf = next_in_directory(leaf))
  927. X      if (leaf->specified)
  928. X           return(leaf);
  929. X     return ((filerec *) NULL);
  930. X}
  931. X
  932. X
  933. X
  934. Xfilerec *first_in_directory(leaf)
  935. Xfilerec *leaf;
  936. X{
  937. X     filerec *ret;
  938. X
  939. X     if ((leaf->specs.st_mode & S_IFMT) != S_IFDIR)
  940. X      ret = (filerec *) NULL;
  941. X     else if (leaf->files)
  942. X      ret = leaf->files;
  943. X     else if (leaf->dirs)
  944. X      ret =  leaf->dirs;
  945. X     else
  946. X      ret = (filerec *) NULL;
  947. X     if (ret) if (ret->freed)
  948. X      ret = next_in_directory(ret);
  949. X     return(ret);
  950. X}
  951. X
  952. X
  953. Xfilerec *first_specified_in_directory(leaf)
  954. Xfilerec *leaf;
  955. X{
  956. X     leaf = first_in_directory(leaf);
  957. X     if (! leaf)
  958. X      return((filerec *) NULL);
  959. X     
  960. X     if (leaf->specified)
  961. X      return(leaf);
  962. X     else
  963. X      leaf = next_specified_in_directory(leaf);
  964. X     return (leaf);
  965. X}
  966. X
  967. X
  968. Xvoid print_paths_from(leaf)
  969. Xfilerec *leaf;
  970. X{
  971. X     char buf[MAXPATHLEN];
  972. X
  973. X     printf("%s\n", get_leaf_path(leaf, buf));
  974. X     if (leaf->dirs)
  975. X      print_paths_from(leaf->dirs);
  976. X     if (leaf->files)
  977. X      print_paths_from(leaf->files);
  978. X     if (leaf->next)
  979. X      print_paths_from(leaf->next);
  980. X}
  981. X
  982. X
  983. Xvoid print_specified_paths_from(leaf)
  984. Xfilerec *leaf;
  985. X{
  986. X     char buf[MAXPATHLEN];
  987. X
  988. X     if (leaf->specified)
  989. X      printf("%s\n", get_leaf_path(leaf, buf));
  990. X     if (leaf->dirs)
  991. X      print_specified_paths_from(leaf->dirs);
  992. X     if (leaf->files)
  993. X      print_specified_paths_from(leaf->files);
  994. X     if (leaf->next)
  995. X      print_specified_paths_from(leaf->next);
  996. X}
  997. X     
  998. X
  999. Xint add_file_to_parent(parent, name, specified, last)
  1000. Xfilerec *parent, **last;
  1001. Xchar *name;
  1002. XBoolean specified;
  1003. X{
  1004. X     filerec *files;
  1005. X
  1006. X     *last = files = (filerec *) NULL;
  1007. X     files = parent->files;
  1008. X     while (files) {
  1009. X      if (! strcmp(files->name, name))
  1010. X           break;
  1011. X      *last = files;
  1012. X      files = files->next;
  1013. X     }
  1014. X     if (files) {
  1015. X      files->specified = (files->specified || specified);
  1016. X      *last = files;
  1017. X      return 0;
  1018. X     }
  1019. X     if (*last) {
  1020. X      (*last)->next = (filerec *) Malloc((unsigned) sizeof(filerec));
  1021. X      if (! (*last)->next) {
  1022. X           set_error(errno);
  1023. X           error("Malloc");
  1024. X           return error_code;
  1025. X      }
  1026. X      *(*last)->next = default_file;
  1027. X      (*last)->next->previous = *last;
  1028. X      (*last)->next->parent = parent;
  1029. X      (*last) = (*last)->next;
  1030. X     }
  1031. X     else {
  1032. X      parent->files = (filerec *) Malloc(sizeof(filerec));
  1033. X      if (! parent->files) {
  1034. X           set_error(errno);
  1035. X           error("Malloc");
  1036. X           return error_code;
  1037. X      }
  1038. X      *parent->files = default_file;
  1039. X      parent->files->parent = parent;
  1040. X      parent->files->previous = (filerec *) NULL;
  1041. X      *last = parent->files;
  1042. X     }
  1043. X     (void) strcpy((*last)->name, name);
  1044. X     (*last)->specified = specified;
  1045. X     return 0;
  1046. X}
  1047. X
  1048. X
  1049. X
  1050. X
  1051. X
  1052. Xint add_directory_to_parent(parent, name, specified, last)
  1053. Xfilerec *parent, **last;
  1054. Xchar *name;
  1055. XBoolean specified;
  1056. X{
  1057. X     filerec *directories;
  1058. X
  1059. X     *last = (filerec *) NULL;
  1060. X     directories = parent->dirs;
  1061. X     while (directories) {
  1062. X      if (! strcmp(directories->name, name))
  1063. X           break;
  1064. X      (*last) = directories;
  1065. X      directories = directories->next;
  1066. X     }
  1067. X     if (directories) {
  1068. X      directories->specified = (directories->specified || specified);
  1069. X      *last = directories;
  1070. X      return 0;
  1071. X     }
  1072. X     if (*last) {
  1073. X      (*last)->next = (filerec *) Malloc(sizeof(filerec));
  1074. X      if (! (*last)->next) {
  1075. X           set_error(errno);
  1076. X           error("Malloc");
  1077. X           return error_code;
  1078. X      }
  1079. X      *(*last)->next = default_directory;
  1080. X      (*last)->next->previous = *last;
  1081. X      (*last)->next->parent = parent;
  1082. X      (*last) = (*last)->next;
  1083. X     }
  1084. X     else {
  1085. X      parent->dirs = (filerec *) Malloc(sizeof(filerec));
  1086. X      if (! parent->dirs) {
  1087. X           set_error(errno);
  1088. X           error("Malloc");
  1089. X           return error_code;
  1090. X      }
  1091. X      *parent->dirs = default_directory;
  1092. X      parent->dirs->parent = parent;
  1093. X      parent->dirs->previous = (filerec *) NULL;
  1094. X      (*last) = parent->dirs;
  1095. X     }
  1096. X     (void) strcpy((*last)->name, name);
  1097. X     (*last)->specified = specified;
  1098. X     return 0;
  1099. X}
  1100. X
  1101. X
  1102. X
  1103. X
  1104. X
  1105. Xvoid free_leaf(leaf)
  1106. Xfilerec *leaf;
  1107. X{
  1108. X     leaf->freed = True;
  1109. X     if (! (leaf->dirs || leaf->files)) {
  1110. X      if (leaf->previous)
  1111. X           leaf->previous->next = leaf->next;
  1112. X      if (leaf->next)
  1113. X           leaf->next->previous = leaf->previous;
  1114. X      if (leaf->parent) {
  1115. X           if ((leaf->specs.st_mode & S_IFMT) == S_IFDIR) {
  1116. X            if (leaf->parent->dirs == leaf) {
  1117. X             leaf->parent->dirs = leaf->next;
  1118. X             if (leaf->parent->freed)
  1119. X                  free_leaf(leaf->parent);
  1120. X            }
  1121. X           }
  1122. X           else {
  1123. X            if (leaf->parent->files == leaf) {
  1124. X             leaf->parent->files = leaf->next;
  1125. X             if (leaf->parent->freed)
  1126. X                  free_leaf(leaf->parent);
  1127. X            }
  1128. X           }
  1129. X           free((char *) leaf);
  1130. X      }
  1131. X     }
  1132. X}     
  1133. X
  1134. X
  1135. X
  1136. Xint find_child(directory, name, child)
  1137. Xfilerec *directory, **child;
  1138. Xchar *name;
  1139. X{
  1140. X     filerec *ptr;
  1141. X     
  1142. X     *child = (filerec *) NULL;
  1143. X     if ((directory->specs.st_mode & S_IFMT) != S_IFDIR)
  1144. X      return DIR_NOT_DIRECTORY;
  1145. X     ptr = directory->dirs;
  1146. X     while (ptr)
  1147. X      if (strcmp(ptr->name, name))
  1148. X           ptr = ptr->next;
  1149. X      else
  1150. X           break;
  1151. X     if (ptr) {
  1152. X      *child = ptr;
  1153. X      return DIR_MATCH;
  1154. X     }
  1155. X     ptr = directory->files;
  1156. X     while (ptr)
  1157. X      if (strcmp(ptr->name, name))
  1158. X           ptr = ptr->next;
  1159. X          else
  1160. X           break;
  1161. X     if (ptr) {
  1162. X      *child = ptr;
  1163. X      return DIR_MATCH;
  1164. X     }
  1165. X     set_status(DIR_NO_MATCH);
  1166. X     return DIR_NO_MATCH;
  1167. X}
  1168. X
  1169. X
  1170. X
  1171. X
  1172. X
  1173. Xint change_path(old_path, new_path)
  1174. Xchar *old_path, *new_path;
  1175. X{
  1176. X     char next_old[MAXNAMLEN], next_new[MAXNAMLEN];
  1177. X     char rest_old[MAXPATHLEN], rest_new[MAXPATHLEN];
  1178. X     int retval;
  1179. X     filerec *current;
  1180. X     
  1181. X     if (*old_path == '/') {
  1182. X      current = &root_tree;
  1183. X      old_path++;
  1184. X      new_path++;
  1185. X     }
  1186. X     else if (! strncmp(old_path, "./", 2)) {
  1187. X      current = &cwd_tree;
  1188. X      old_path += 2;
  1189. X      new_path += 2;
  1190. X     }
  1191. X     else
  1192. X      current = &cwd_tree;
  1193. X     
  1194. X     (void) strcpy(next_old, firstpart(old_path, rest_old));
  1195. X     (void) strcpy(next_new, firstpart(new_path, rest_new));
  1196. X     while (*next_old && *next_new) {
  1197. X      retval = find_child(current, next_old, ¤t);
  1198. X      if (retval == DIR_MATCH) {
  1199. X           if (current) {
  1200. X            (void) strcpy(current->name, next_new);
  1201. X            current->specified = False;
  1202. X           }
  1203. X           else {
  1204. X            set_error(INTERNAL_ERROR);
  1205. X            error("change_path");
  1206. X            return error_code;
  1207. X           }
  1208. X      }
  1209. X      else {
  1210. X           error("change_path");
  1211. X           return retval;
  1212. X      }
  1213. X      
  1214. X      (void) strcpy(next_old, firstpart(rest_old, rest_old));
  1215. X      (void) strcpy(next_new, firstpart(rest_new, rest_new));
  1216. X     }
  1217. X     return 0;
  1218. X}
  1219. X
  1220. X
  1221. Xint get_leaf_path(leaf, leaf_buf)
  1222. Xfilerec *leaf;
  1223. Xchar leaf_buf[]; /* RETURN */
  1224. X{
  1225. X     char *name_ptr;
  1226. X
  1227. X     name_ptr = Malloc(1);
  1228. X     if (! name_ptr) {
  1229. X      set_error(errno);
  1230. X      error("Malloc");
  1231. X      *leaf_buf = '\0';
  1232. X      return error_code;
  1233. X     }
  1234. X     *name_ptr = '\0';
  1235. X     do {
  1236. X      name_ptr = realloc((char *) name_ptr, (unsigned)
  1237. X                 (strlen(leaf->name) + strlen(name_ptr) + 2));
  1238. X      if (! name_ptr) {
  1239. X           set_error(errno);
  1240. X           *leaf_buf = '\0';
  1241. X           error("realloc");
  1242. X           return error_code;
  1243. X      }
  1244. X      (void) strcpy(leaf_buf, name_ptr);
  1245. X      *name_ptr = '\0';
  1246. X      if (leaf->parent) if (leaf->parent->parent)
  1247. X           (void) strcat(name_ptr, "/");
  1248. X      (void) strcat(name_ptr, leaf->name);
  1249. X      (void) strcat(name_ptr, leaf_buf);
  1250. X      leaf = leaf->parent;
  1251. X     } while (leaf);
  1252. X     (void) strcpy(leaf_buf, name_ptr);
  1253. X     return 0;
  1254. X}
  1255. X
  1256. X
  1257. X
  1258. X
  1259. X
  1260. Xint accumulate_names(leaf, in_strings, num)
  1261. Xfilerec *leaf;
  1262. Xchar ***in_strings;
  1263. Xint *num;
  1264. X{
  1265. X     char newname[MAXPATHLEN];
  1266. X     char **strings;
  1267. X     int retval;
  1268. X     
  1269. X     strings = *in_strings;
  1270. X     if (leaf->specified) {
  1271. X      *num += 1;
  1272. X      strings = (char **) realloc((char *) strings, (unsigned)
  1273. X                      (sizeof(char *) * (*num)));
  1274. X      if (! strings) {
  1275. X           set_error(errno);
  1276. X           error("realloc");
  1277. X           return error_code;
  1278. X      }
  1279. X      if (retval = get_leaf_path(leaf, newname)) {
  1280. X           error("get_leaf_path");
  1281. X           return retval;
  1282. X      }
  1283. X      (void) convert_to_user_name(newname, newname);
  1284. X      strings[*num - 1] = Malloc((unsigned) (strlen(newname) + 1));
  1285. X      if (! strings[*num - 1]) {
  1286. X           set_error(errno);
  1287. X           error("Malloc");
  1288. X           return error_code;
  1289. X      }
  1290. X      (void) strcpy(strings[*num - 1], newname);
  1291. X     }
  1292. X     if (leaf->files) if (retval = accumulate_names(leaf->files, &strings,
  1293. X                            num)) {
  1294. X      error("accumulate_names");
  1295. X      return retval;
  1296. X     }
  1297. X     if (leaf->dirs) if (retval = accumulate_names(leaf->dirs, &strings,
  1298. X                           num)) {
  1299. X      error("accumulate_names");
  1300. X      return retval;
  1301. X     }
  1302. X     if (leaf->next) if (retval = accumulate_names(leaf->next, &strings,
  1303. X                           num)) {
  1304. X      error("accumulate_names");
  1305. X      return retval;
  1306. X     }
  1307. X
  1308. X     *in_strings = strings;
  1309. X     return 0;
  1310. X}
  1311. END_OF_FILE
  1312. if test 15169 -ne `wc -c <'directories.c'`; then
  1313.     echo shar: \"'directories.c'\" unpacked with wrong size!
  1314. fi
  1315. # end of 'directories.c'
  1316. fi
  1317. echo shar: End of archive 3 \(of 4\).
  1318. cp /dev/null ark3isdone
  1319. MISSING=""
  1320. for I in 1 2 3 4 ; do
  1321.     if test ! -f ark${I}isdone ; then
  1322.     MISSING="${MISSING} ${I}"
  1323.     fi
  1324. done
  1325. if test "${MISSING}" = "" ; then
  1326.     echo You have unpacked all 4 archives.
  1327.     rm -f ark[1-9]isdone
  1328. else
  1329.     echo You still need to unpack the following archives:
  1330.     echo "        " ${MISSING}
  1331. fi
  1332. ##  End of shell archive.
  1333. exit 0
  1334.  
  1335. exit 0 # Just in case...
  1336. -- 
  1337. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1338. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1339. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1340. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1341.